
与函数模板一样，在头文件中声明并定义Stack<>类，如下所示:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/stack1.hpp}
\begin{lstlisting}[style=styleCXX]
#include <vector>
#include <cassert>

template<typename T>
class Stack {
private:
	std::vector<T> elems; // elements
	
public:
	void push(T const& elem); // push element
	void pop(); // pop element
	T const& top() const; // return top element
	bool empty() const { // return whether the stack is empty
		return elems.empty();
	}
};

template<typename T>
void Stack<T>::push (T const& elem)
{
	elems.push_back(elem); // append copy of passed elem
}

template<typename T>
void Stack<T>::pop ()
{
	assert(!elems.empty());
	elems.pop_back(); // remove last element
}

template<typename T>
T const& Stack<T>::top () const
{
	assert(!elems.empty());
	return elems.back(); // return copy of last element
}
\end{lstlisting}

类模板使用C++标准库的vector<>实现。因此，不必实现内存管理、复制构造函数和赋值操作符，可以专注于该类模板的接口。

\subsubsubsection{2.1.1\hspace{0.2cm}声明类模板}

声明类模板类似于声明函数模板。声明前，必须将一个或多个标识符声明为类型参数。同样，T作为常用标识符:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
	...
};
\end{lstlisting}

这里，关键字class也可以替换typename:

\begin{lstlisting}[style=styleCXX]
template<class T>
class Stack {
	...
};
\end{lstlisting}

类模板内部，可以像使用其他类型一样使用T来声明成员和成员函数。这个例子中，T用来声明元素的类型为T的vector，将push()声明为使用T作参数的成员函数，并将top()声明为返回T的函数:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
private:
	std::vector<T> elems; // elements
	
public:
	void push(T const& elem); // push element
	void pop(); // pop element
	T const& top() const; // return top element
	bool empty() const { // return whether the stack is empty
		return elems.empty();
	}
};
\end{lstlisting}

这个类的类型是Stack<T>，T是模板参数。因此，只要在使用该类的类型，就必须使用Stack<T>声明，可以推导模板参数的情况除外。但在类模板中使用类名(不带模板参数)，表明这个内部类的模板参数类型和模板类的参数类型相同(详见第13.2.3节)。

例如，必须声明自定义的复制构造函数和赋值操作符:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
	...
	Stack (Stack const&); // copy constructor
	Stack& operator= (Stack const&); // assignment operator
	...
};
\end{lstlisting}

形式上等价于:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
	...
	Stack (Stack<T> const&); // copy constructor
	Stack<T>& operator= (Stack<T> const&); // assignment operator
	...
};
\end{lstlisting}

通常<T>表示特殊模板参数，所以最好使用第一种方式。

这里，

\begin{lstlisting}[style=styleCXX]
template<typename T>
bool operator== (Stack<T> const& lhs, Stack<T> const& rhs);
\end{lstlisting}

在需要类名而不是类类型的地方，只能使用Stack。尤其是，指定构造函数的名称(而不是参数)和析构函数时。

与非模板类不同，不能在函数或块作用域内声明或定义类模板。通常，模板只能在全局/命名空间作用域或类中声明内部定义(参见12.1节了解详细信息)。

\subsubsubsection{2.1.2\hspace{0.2cm}成员函数}

要定义类模板的成员函数，必须将其指定为模板，并且使用类模板对类型进行限定。因此，Stack<T>类型的成员函数push()实现如下所示:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void Stack<T>::push (T const& elem)
{
	elems.push_back(elem); // append copy of passed elem
}
\end{lstlisting}

使用vector的push\_back()，将元素添加到vector的末尾。

注意，vector的pop\_back()会删除最后一个元素，但不返回这个元素，这种行为是异常安全的。使用pop()的完全异常安全版本，来返回删除元素是不可能的(这个问题由Tom Cargill在[CargillExceptionSafety]中首次提出，并在[sutterexception]中的第10项中进行讨论)。这里可以忽略这个危险，可以实现pop()返回刚刚删除的元素。为此，只需使用T声明元素类型的局部变量即可:

\begin{lstlisting}[style=styleCXX]
template<typename T>
T Stack<T>::pop ()
{
	assert(!elems.empty());
	T elem = elems.back(); // save copy of last element
	elems.pop_back(); // remove last element
	return elem; // return copy of saved element
}
\end{lstlisting}

当vector中没有元素时，back()(返回最后一个元素)和pop\_back()(删除最后一个元素)会导致未定义行为，所以先检查堆栈是否为空。如果为空，则触发断言，因为在空堆栈上调用pop()是一个使用错误。top()也是这样，当试图删除一个不存在的top元素时，top()会返回但不删除top元素:

\begin{lstlisting}[style=styleCXX]
template<typename T>
T const& Stack<T>::top () const
{
	assert(!elems.empty());
	return elems.back(); // return last element
}
\end{lstlisting}

当然，对于成员函数，可以在类声明中以内联的形式，实现类模板的成员函数。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
	...
	void push (T const& elem) {
		elems.push_back(elem); // append copy of passed elem
	}
	...
};
\end{lstlisting}






